花了很多的篇幅介紹 Subdomain 與 Bounded Context,本篇想藉由一個比喻跟案例來加深大家的理解!
本篇涵蓋:
回顧前,你可以先拿出紙筆、打開編輯器或是面對你家的貓,開始回答以下十題。
讀者們可以先看完問題後先自己思考,再往下看我的答案。
- 請說明 Domain 是什麼?
Domain 是你工作所面對的問題與解法。分為 Problem Space 與 Solution Space 兩個空間。
- 請說明 Ubiquitous Language 的定義與好處以及如何產出?
當團隊內對於領域內的概念有清晰且一致的用詞時,代表團隊正在使用 Ubiquitous Language。
它可以提升開發團隊與領域專家的溝通品質,甚至可以應用在溝通時、文件中、程式裡。
Ubiquitous Language 會經由與領域專家甚至是與客戶反復溝通捕捉使用案例所得出。同時 Ubiquitous Language 也需要不斷的錘鍊以符合需求的改變。
- 請問 Problem Space 與 Solution Space 是什麼?
Problem Space 代表著領域要解決的問題,而我們需要進一步分解它成數個 Subdomain,並依照優先度與外包程度分為: Core Domain、Supporting Subdomain、Generic Subdomain。
Solution Space 代表領域的解決方案,我們會在裡面開發多個 Domain Models 來解決問題。而 Domain Models 需要被隔離在 Bounded Context 中以保證 Model 與 Ubiquitous Language 的一致性。
- 請說明 Core Domain、Supporting Subdomain、Generic Subdomain 的定義與差異。
Core Domain 代表整個系統最有價值且不能被輕易取代的部分,通常企業需要花費最多心力在上面。
Supporting Subdomain 雖然不是系統最有價值的部分但仍支援核心完成任務。
Generic Subdomain 同樣也不是最有價值的部分,且通常市場上已有成熟的解決方案,通常可以外包出去。
最後,這三者有優先程度但**都很重要!**缺乏任何一個系統都會失敗。
- 承上題,請為你目前的工作領域來繪製簡單的 Problem Space。並找出其中的 Core Domain。
動手試試看,或是參考下面的電影院比喻。
- 請說明 Bounded Context 的意義以及對於程式碼的影響。以及如何找出來?
Bounded Context 為解決方案的 Domain Models 建立了一個語意的邊界,讓在其中的 Domain Models 在資料與行為上都能符合 Ubiquitous Language 以及業務需求。
對於找出 Bounded Context,主要以語意與業務能力來重點。可以從找出那些使用相近概念的名詞與在不同情境下的會有歧異的名詞下手,同時也可以藉由分析系統功能的步驟來解析出 Bounded Context。
- 請說明 Subdomain 與 Bounded Context 間的差別。
Subdomain 你將商業需求拆解與分類的結果;而 Bounded Context 代表你實際解決問題的系統拆解與分類。
有時候這兩者緊緊相關很容易搞混,但他們的確是不同的東西。可以參考 DDD 之父 Eric Evans 在這篇 youtube video 的簡短回答。裡面提到:
這就像地板與地毯的關係。地板是 Subdomain, Bounded Context 是地毯。當你剛裝修好新家就像剛啟動專案時,地毯設計與地板完全匹配,所以你很難發覺他們的差異。但兩者的確是不同的東西。
但有一天你換了一個新地毯,它可能無法百分百與地板匹配,會露出一些地板的原貌,甚至會被一些傢俱 (Legacy System) 給擋住,讓兩者更難貼合,此時兩著的差異才會漸漸浮現。
聽完實作還是不會怎麼辦?沒關係。簡單來說如果你在實作時遇到困難時,就不用分那麼細了,找到一個你和開發團隊都舒服的方式即可。
- 請說出 Context Mapping 的所有模式以及大致的功能。
- 承 5. 把 Bounded Context 以及 Context Mapping 也一併畫出來
動手試試看,或是參考下面的電影院比喻。
- 請說出你心中的其他疑問,然後在下方留言,我會找時間一一回覆。
剛開始接觸 DDD 時,因為 Strategic Design 不會碰到實際的程式碼,所以花了很久的時間才搞懂 Domain、Subdomain、Ubiquitous Language、Bounded Context 的意義與差別。
所以我想用一個現實生活的簡單比喻來為大家說明:蓋一家電影院吧!
領域專家變成電影院的出資方,我們則是變成建築工人。一開始先進入需求訪談
出資方說:
我希望能夠成立一家電影院,這個電影院必須要有**售票亭**可以售票給顧客。售票時,員工要檢查**顧客的身分證、時間、電影、座位**等等。然後因應 APP 的風潮,所以我們想要跟第**三方訂票軟體**合作,利用線上預約現場售票處取票。當然,電影院一定要有**放映廳**,要進去放映廳前會有員工**檢查消費者的票**是否符合目前播放的電影。再來, 客人在售票處買電影票時也可以添加**食物套餐**,然後你可以憑票去**飲食部**換取你的食物,飲食部需要與售票處獨立出來,因為飲食部還需要**管理食物的庫存**...
如果你看完覺得很冗長,我說,這才是真實世界的情境!你可以發現就連領域專家本人在講話時可能都沒有統一他的語言,一個名詞有多種說法(ex: 顧客、客人、消費者)。所以當你套用 DDD 時,為了要建立 Ubiquitous Language 與 Bounded Context ,你就會開始注意這些語言細節,也開始要求領域專家與開發團隊都要用 Ubiquitous Language 溝通。
比如,「客人」、「售票亭」、「飲食部」、「放映廳」、「員工」等名稱要統一。
接著在你來我往的需求訪談後,我們可以發現領域專家有三個主要需求:電影、售票、食物。其中放映廳是這家電影院的主要競爭力 (Core Domain),而售票與食物部分並未全部外包出去,因此算是 Supporting Subdomain。
(找出 Subdomains)
再經過更深度的使用案例訪談後,我們從上述的需求訪談裡面列出了幾項關鍵使用案例:
有了以上的關鍵使用案例,我們可以描繪出以下 Bounded Context:
(建立 Bounded Context 並定義依賴關係)
差個曲,如果哪一天出資方決定要將售票服務或是餐飲服務整個外包出去時,該 Subdomain 可能就會成為 Generic Subdomain。
接者當你開始在 Bounded Context 中開發 Domain Model 時,可以發現一件有趣的事情:一個電影票券在不同的 Bounded Context 中有不一樣的行爲。可以參考下圖:
(一個 Ticket 各自表述)
這邊想引用 Patterns, Principles, and Practices of Domain-Driven Design (簡稱 3PoDDD) 裡面對於 Subdomain 與 Bounded Context 差別的論述,以下我用中文翻譯:
Subdomain 代表著一塊邏輯上的需求域,通常來說反映出企業組織架構的業務能力。他們被用來區別應用程式不同重要程度的部分如 Core Domain 以及稍微不重要的 Supporting Subdomain 。Subdomain 是用來提煉出問題空間的精華並解構其中的複雜。
Domain Model 則是被建立來滿足各個 Subdomain 的使用案例。理想上 Model 與 Subdomain 間會有一比一的對應關係,但是很難實現。Model 會受到組織架構、語言的模糊性、商業流程或是開發模式的影響。因此一個 Subdomain 可能會包含一個至多個 Model ,而一個 Model 也有可能跨越多個 Subdomain。這種事情很常見於 Legacy System 的環境中。
Models 需要被隔離並在一個明確的(explicit)邊界內被定義,如此才能讓 Model 不受污染且專注。就像前面所說,這就是我們的 Bounded Context。不像是 Subdomain,一個 Bounded Context 是一個能保證 Model 間邊界的具體的技術實作。 Bounded Context 存在於 Subdomain 中並在其中明確的表達 Domain Models 的含義。
你好,在下 DDD 新手,想請教一個問題
上面有提到說, Context Mapping 其中的 shared kernel 會讓兩個不同的 Bounded Context 會有共同的程式碼,那在這時候 subdomain 的關係又是甚麼呢? 他們會重疊嗎? 還是會有另一個 subdomain 代表這個 shared kernel?
分享我的看法給 @hungyanbin 。
這個問題答案是不一定,要看當時的狀況,也就是這兩個 Bounded Context 與 Subdomain 當下對應的結果。
在 IDDD 的 Domain 與 Bounded Context 章節有提到,一個 Subdomain 理想上是對應一個 Bounded Context。但也因為現實中的問題通常很複雜,因此通常來說一個 Subdomain 會由多個 Bounded Context 來實現。
所以若兩個 Bounded Context 分別在兩個不同的 Subdomain 的情況下,此時在 Shared Kernel 所提到的這兩個 Bounded Context 重疊也代表兩個 Subdomain 的重疊。
但若因為一個 Subdomain 中的問題空間比較大,發生需要兩個以上的 Bounded Context 實現時,也就會是在同一個 Subdomain 下 :)
感謝 EasonKuo 的解釋,我的想法跟他差不多。
Subdomain 就像是一個抽象的問題空間,你可以放入一到多個解決方案去解決它 (有時候甚至一個解決方案會跨到兩個以上 Subdomain)。Shared Kernel 指的是 Bounded Context 間的關係,其實跟 Subdomain 沒有關係。